home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / ftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  9.7 KB  |  462 lines

  1. #if HAVE_CONFIG_H
  2. # include "config.h"
  3. #else
  4. #define HAVE_MACHINE_TYPES_H 1
  5. #define HAVE_ALLOCA_H 1
  6. #define HAVE_NETINET_IN_SYSTM_H 1
  7. #endif
  8.  
  9. #if HAVE_MACHINE_TYPES_H
  10. # include <machine/types.h>
  11. #endif
  12.  
  13. #if HAVE_ALLOCA_H
  14. # include <alloca.h>
  15. #endif
  16.  
  17. #if HAVE_NETINET_IN_SYSTM_H
  18. # include <sys/types.h>
  19. # include <netinet/in_systm.h>
  20. #endif
  21.  
  22. #if ! HAVE_HERRNO
  23. extern int h_errno;
  24. #endif
  25.  
  26. #include <ctype.h>
  27. #include <errno.h>
  28. #include <fcntl.h>
  29. #include <netdb.h>
  30. #include <pwd.h>
  31. #include <stdarg.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/socket.h>
  36. #include <sys/time.h>
  37. #include <sys/types.h>
  38. #include <unistd.h>
  39.  
  40. #include <netinet/in.h>
  41. #include <netinet/ip.h>
  42. #include <arpa/inet.h>
  43.  
  44. #include "inet_aton.h"        /* for systems too stupid to provide this */
  45.  
  46. #define TIMEOUT_SECS 60
  47. #define BUFFER_SIZE 4096
  48.  
  49. #ifndef IPPORT_FTP
  50. # define IPPORT_FTP 21
  51. #endif
  52.  
  53. #include "ftp.h"
  54.  
  55. static int ftpCheckResponse(int sock, char ** str);
  56. static int ftpCommand(int sock, char * command, ...);
  57. static int ftpReadData(int sock, int out);
  58. static int getHostAddress(const char * host, struct in_addr * address);
  59.  
  60. static int ftpCheckResponse(int sock, char ** str) {
  61.     static char buf[BUFFER_SIZE + 1];
  62.     int bufLength = 0; 
  63.     fd_set emptySet, readSet;
  64.     char * chptr, * start;
  65.     struct timeval timeout;
  66.     int bytesRead, rc = 0;
  67.     int doesContinue = 1;
  68.     char errorCode[4];
  69.  
  70.     errorCode[0] = '\0';
  71.     
  72.     do {
  73.     FD_ZERO(&emptySet);
  74.     FD_ZERO(&readSet);
  75.     FD_SET(sock, &readSet);
  76.  
  77.     timeout.tv_sec = TIMEOUT_SECS;
  78.     timeout.tv_usec = 0;
  79.     
  80.     rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
  81.     if (rc < 1) {
  82.         if (rc==0) 
  83.         return FTPERR_BAD_SERVER_RESPONSE;
  84.         else
  85.         rc = FTPERR_UNKNOWN;
  86.     } else
  87.         rc = 0;
  88.  
  89.     bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
  90.  
  91.     bufLength += bytesRead;
  92.  
  93.     buf[bufLength] = '\0';
  94.  
  95.     /* divide the response into lines, checking each one to see if 
  96.        we are finished or need to continue */
  97.  
  98.     start = chptr = buf;
  99.  
  100.     do {
  101.         while (*chptr != '\n' && *chptr) chptr++;
  102.  
  103.         if (*chptr == '\n') {
  104.         *chptr = '\0';
  105.         if (*(chptr - 1) == '\r') *(chptr - 1) = '\0';
  106.         if (str) *str = start;
  107.  
  108.         if (errorCode[0]) {
  109.             if (!strncmp(start, errorCode, 3) && start[3] == ' ')
  110.             doesContinue = 0;
  111.         } else {
  112.             strncpy(errorCode, start, 3);
  113.             errorCode[3] = '\0';
  114.             if (start[3] != '-') {
  115.             doesContinue = 0;
  116.             } 
  117.         }
  118.  
  119.         start = chptr + 1;
  120.         chptr++;
  121.         } else {
  122.         chptr++;
  123.         }
  124.     } while (*chptr);
  125.  
  126.     if (doesContinue && chptr > start) {
  127.         memcpy(buf, start, chptr - start - 1);
  128.         bufLength = chptr - start - 1;
  129.     } else {
  130.         bufLength = 0;
  131.     }
  132.     } while (doesContinue && !rc);
  133.  
  134.     if (*errorCode == '4' || *errorCode == '5') {
  135.     if (!strncmp(errorCode, "550", 3)) {
  136.         return FTPERR_FILE_NOT_FOUND;
  137.     }
  138.  
  139.     return FTPERR_BAD_SERVER_RESPONSE;
  140.     }
  141.  
  142.     if (rc) return rc;
  143.  
  144.     return 0;
  145. }
  146.  
  147. int ftpCommand(int sock, char * command, ...) {
  148.     va_list ap;
  149.     int len;
  150.     char * s;
  151.     char * buf;
  152.     int rc;
  153.  
  154.     va_start(ap, command);
  155.     len = strlen(command) + 2;
  156.     s = va_arg(ap, char *);
  157.     while (s) {
  158.     len += strlen(s) + 1;
  159.     s = va_arg(ap, char *);
  160.     }
  161.     va_end(ap);
  162.  
  163.     buf = alloca(len + 1);
  164.  
  165.     va_start(ap, command);
  166.     strcpy(buf, command);
  167.     strcat(buf, " ");
  168.     s = va_arg(ap, char *);
  169.     while (s) {
  170.     strcat(buf, s);
  171.     strcat(buf, " ");
  172.     s = va_arg(ap, char *);
  173.     }
  174.     va_end(ap);
  175.  
  176.     buf[len - 2] = '\r';
  177.     buf[len - 1] = '\n';
  178.     buf[len] = '\0';
  179.      
  180.     if (write(sock, buf, len) != len) {
  181.         return FTPERR_SERVER_IO_ERROR;
  182.     }
  183.  
  184.     if ((rc = ftpCheckResponse(sock, NULL)))
  185.     return rc;
  186.  
  187.     return 0;
  188. }
  189.  
  190. static int getHostAddress(const char * host, struct in_addr * address) {
  191.     struct hostent * hostinfo;
  192.  
  193.     if (isdigit(host[0])) {
  194.       if (!inet_aton(host, address)) {
  195.       return FTPERR_BAD_HOST_ADDR;
  196.       }
  197.     } else {
  198.       hostinfo = gethostbyname(host);
  199.       if (!hostinfo) {
  200.       errno = h_errno;
  201.       return FTPERR_BAD_HOSTNAME;
  202.       }
  203.       
  204.       memcpy(address, hostinfo->h_addr_list[0], hostinfo->h_length);
  205.     }
  206.     
  207.     return 0;
  208. }
  209.  
  210. int ftpOpen(char * host, char * name, char * password, char * proxy,
  211.         int port) {
  212.     static int sock;
  213.     /*static char * lastHost = NULL;*/
  214.     struct in_addr serverAddress;
  215.     struct sockaddr_in destPort;
  216.     struct passwd * pw;
  217.     char * buf;
  218.     int rc;
  219.  
  220.     if (port < 0) port = IPPORT_FTP;
  221.  
  222.     if (!name)
  223.     name = "anonymous";
  224.  
  225.     if (!password) {
  226.     if (getuid()) {
  227.         pw = getpwuid(getuid());
  228.         password = alloca(strlen(pw->pw_name) + 2);
  229.         strcpy(password, pw->pw_name);
  230.         strcat(password, "@");
  231.     } else {
  232.         password = "root@";
  233.     }
  234.     }
  235.  
  236.     if (proxy) {
  237.     buf = alloca(strlen(name) + strlen(host) + 5);
  238.     sprintf(buf, "%s@%s", name, host);
  239.     name = buf;
  240.     host = proxy;
  241.     }
  242.  
  243.     if ((rc = getHostAddress(host, &serverAddress))) return rc;
  244.  
  245.     sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  246.     if (sock < 0) {
  247.         return FTPERR_FAILED_CONNECT;
  248.     }
  249.  
  250.     destPort.sin_family = AF_INET;
  251.     destPort.sin_port = htons(port);
  252.     destPort.sin_addr = serverAddress;
  253.  
  254.     if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
  255.     close(sock);
  256.         return FTPERR_FAILED_CONNECT;
  257.     }
  258.  
  259.     /* ftpCheckResponse() assumes the socket is nonblocking */
  260.     if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
  261.     close(sock);
  262.         return FTPERR_FAILED_CONNECT;
  263.     }
  264.  
  265.     if ((rc = ftpCheckResponse(sock, NULL))) {
  266.         return rc;     
  267.     }
  268.  
  269.     if ((rc = ftpCommand(sock, "USER", name, NULL))) {
  270.     close(sock);
  271.     return rc;
  272.     }
  273.  
  274.     if ((rc = ftpCommand(sock, "PASS", password, NULL))) {
  275.     close(sock);
  276.     return rc;
  277.     }
  278.  
  279.     if ((rc = ftpCommand(sock, "TYPE", "I", NULL))) {
  280.     close(sock);
  281.     return rc;
  282.     }
  283.  
  284.     return sock;
  285. }
  286.  
  287. int ftpReadData(int sock, int out) {
  288.     char buf[BUFFER_SIZE];
  289.     fd_set emptySet, readSet;
  290.     struct timeval timeout;
  291.     int bytesRead, rc;
  292.     
  293.     while (1) {
  294.     FD_ZERO(&emptySet);
  295.     FD_ZERO(&readSet);
  296.     FD_SET(sock, &readSet);
  297.  
  298.     timeout.tv_sec = TIMEOUT_SECS;
  299.     timeout.tv_usec = 0;
  300.     
  301.     rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
  302.     if (rc == 0) {
  303.         close(sock);
  304.         return FTPERR_SERVER_TIMEOUT;
  305.     } else if (rc < 0) {
  306.         close(sock);
  307.         return FTPERR_UNKNOWN;
  308.     }
  309.  
  310.     bytesRead = read(sock, buf, sizeof(buf));
  311.     if (bytesRead == 0) {
  312.         close(sock);
  313.         return 0;
  314.     }
  315.  
  316.     if (write(out, buf, bytesRead) != bytesRead) {
  317.         close(sock);
  318.         return FTPERR_FILE_IO_ERROR;
  319.     }
  320.     }
  321. }
  322.  
  323. int ftpGetFileDesc(int sock, char * remotename) {
  324.     int dataSocket;
  325.     struct sockaddr_in dataAddress;
  326.     int i, j;
  327.     char * passReply;
  328.     char * chptr;
  329.     char * retrCommand;
  330.     int rc;
  331.  
  332.     if (write(sock, "PASV\r\n", 6) != 6) {
  333.         return FTPERR_SERVER_IO_ERROR;
  334.     }
  335.     if ((rc = ftpCheckResponse(sock, &passReply)))
  336.     return FTPERR_PASSIVE_ERROR;
  337.  
  338.     chptr = passReply;
  339.     while (*chptr && *chptr != '(') chptr++;
  340.     if (*chptr != '(') return FTPERR_PASSIVE_ERROR; 
  341.     chptr++;
  342.     passReply = chptr;
  343.     while (*chptr && *chptr != ')') chptr++;
  344.     if (*chptr != ')') return FTPERR_PASSIVE_ERROR;
  345.     *chptr-- = '\0';
  346.  
  347.     while (*chptr && *chptr != ',') chptr--;
  348.     if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
  349.     chptr--;
  350.     while (*chptr && *chptr != ',') chptr--;
  351.     if (*chptr != ',') return FTPERR_PASSIVE_ERROR;
  352.     *chptr++ = '\0';
  353.     
  354.     /* now passReply points to the IP portion, and chptr points to the
  355.        port number portion */
  356.  
  357.     dataAddress.sin_family = AF_INET;
  358.     if (sscanf(chptr, "%d,%d", &i, &j) != 2) {
  359.     return FTPERR_PASSIVE_ERROR;
  360.     }
  361.     dataAddress.sin_port = htons((i << 8) + j);
  362.  
  363.     chptr = passReply;
  364.     while (*chptr++) {
  365.     if (*chptr == ',') *chptr = '.';
  366.     }
  367.  
  368.     if (!inet_aton(passReply, &dataAddress.sin_addr)) 
  369.     return FTPERR_PASSIVE_ERROR;
  370.  
  371.     dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  372.     if (dataSocket < 0) {
  373.         return FTPERR_FAILED_CONNECT;
  374.     }
  375.  
  376.     retrCommand = alloca(strlen(remotename) + 20);
  377.     sprintf(retrCommand, "RETR %s\r\n", remotename);
  378.     i = strlen(retrCommand);
  379.    
  380.     if (write(sock, retrCommand, i) != i) {
  381.         return FTPERR_SERVER_IO_ERROR;
  382.     }
  383.  
  384.     if (connect(dataSocket, (struct sockaddr *) &dataAddress, 
  385.             sizeof(dataAddress))) {
  386.     close(dataSocket);
  387.         return FTPERR_FAILED_DATA_CONNECT;
  388.     }
  389.  
  390.     if ((rc = ftpCheckResponse(sock, NULL))) {
  391.     close(dataSocket);
  392.     return rc;
  393.     }
  394.  
  395.     return dataSocket;
  396. }
  397.  
  398. int ftpGetFileDone(int sock) {
  399.     if (ftpCheckResponse(sock, NULL)) {
  400.     return FTPERR_BAD_SERVER_RESPONSE;
  401.     }
  402.  
  403.     return 0;
  404. }
  405.  
  406. int ftpGetFile(int sock, char * remotename, int dest) {
  407.     int dataSocket, rc;
  408.  
  409.     dataSocket = ftpGetFileDesc(sock, remotename);
  410.     if (dataSocket < 0) return dataSocket;
  411.  
  412.     rc = ftpReadData(dataSocket, dest);
  413.     close(dataSocket);
  414.     
  415.     if (rc) return rc;
  416.  
  417.     return ftpGetFileDone(sock);
  418. }
  419.  
  420. void ftpClose(int sock) {
  421.     close(sock);
  422. }
  423.  
  424. const char *ftpStrerror(int errorNumber) {
  425.   switch (errorNumber) {
  426.     case FTPERR_BAD_SERVER_RESPONSE:
  427.       return ("Bad FTP server response");
  428.  
  429.     case FTPERR_SERVER_IO_ERROR:
  430.       return("FTP IO error");
  431.  
  432.     case FTPERR_SERVER_TIMEOUT:
  433.       return("FTP server timeout");
  434.  
  435.     case FTPERR_BAD_HOST_ADDR:
  436.       return("Unable to lookup FTP server host address");
  437.  
  438.     case FTPERR_BAD_HOSTNAME:
  439.       return("Unable to lookup FTP server host name");
  440.  
  441.     case FTPERR_FAILED_CONNECT:
  442.       return("Failed to connect to FTP server");
  443.  
  444.     case FTPERR_FAILED_DATA_CONNECT:
  445.       return("Failed to establish data connection to FTP server");
  446.  
  447.     case FTPERR_FILE_IO_ERROR:
  448.       return("IO error to local file");
  449.  
  450.     case FTPERR_PASSIVE_ERROR:
  451.       return("Error setting remote server to passive mode");
  452.  
  453.     case FTPERR_FILE_NOT_FOUND:
  454.       return("File not found on server");
  455.  
  456.     case FTPERR_UNKNOWN:
  457.     default:
  458.       return("FTP Unknown or unexpected error");
  459.   }
  460. }
  461.   
  462.